#ifndef BASIC_DISPATCHER_H
#define BASIC_DISPATCHER_H

#include "TypeInfo.h"
#include <utility>
#include <map>
#include <stdexcept>

template<class BaseLhs, class BaseRhs = BaseLhs, typename ResultType = void,
	typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&)>
class BasicDispatcher
{
	typedef std::pair<TypeInfo, TypeInfo> KeyType;
	typedef ResultType (*CallbackType)(BaseLhs&, BaseRhs&);
	typedef CallbackType MappedType;
	typedef std::map<KeyType,MappedType> ValueType;
	ValueType callbackMap_;
public:
	template<class SomeLhs, class SomeRhs> void Add(CallbackType fun);
	ResultType Go(BaseLhs& lhs, BaseRhs& rhs);
};

template<class BaseLhs, class BaseRhs, typename ResultType, typename CallbackType>
template<class SomeLhs, class SomeRhs>
void BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>::Add(CallbackType fun)
{
	const KeyType key(typeid(SomeLhs), typeid(SomeRhs));
	callbackMap_[key] = fun;
}

template<class BaseLhs, class BaseRhs, typename ResultType, typename CallbackType>
ResultType BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>::Go(BaseLhs& lhs, BaseRhs& rhs)
{
	typename ValueType::iterator i = callbackMap_.find(KeyType(typeid(lhs),typeid(rhs)));
	if (i == callbackMap_.end() )
		throw std::runtime_error("Function not found");
	return (i->second)(lhs,rhs);
}



#endif